﻿#include "Date.hpp"
#include <iomanip>
#include <sstream>
#include <ctime>
#include <time.h>

Date::Date() {
    set(std::chrono::system_clock::now());
}
Date::Date(const std::chrono::system_clock::time_point& time) {
    set(time);
}
Date::Date(const time_t& time) {
    set(std::gmtime(&time));
}
Date::Date(const std::tm* tm) {
    set(tm);
}
Date::Date(const std::string& text, const char* format/*=nullptr*/) {
    set(text, format);
}
Date::Date(const std::array<uint16_t, 6>& date) {
    set(date);
}
Date::Date(const Date& date) {
    set(date);
}

void Date::set(const std::chrono::system_clock::time_point& time) {
    set(std::chrono::system_clock::to_time_t(time));
}
void Date::set(const time_t& time) {
    set(std::gmtime(&time));
}
void Date::set(const std::tm* tm) {
    this->year() = tm->tm_year + 1900;
    this->month() = tm->tm_mon;
    this->day() = tm->tm_mday - 1;
    this->hour() = tm->tm_hour;
    this->minute() = tm->tm_min;
    this->second() = tm->tm_sec;
}
void Date::set(const std::string& t, const char* format/*=nullptr*/) {
    if (format && ::strlen(format)) {
        std::tm tm;
#ifdef __APPLE__
        if (::strptime(t.c_str(), format, &tm)) {
            new (this)Date(&tm);
        }
#endif
    } else {
        new (this)Date((time_t)std::stol(t));
    }
}
void Date::set(const std::array<uint16_t, 6>& date) {
    for (size_t i=0; i!=date.size(); ++i) {
        (*this)[i] = date[i];
    }
}
void Date::set(const Date& date) {
    for (size_t i=0; i!=date.size(); ++i) {
        (*this)[i] = date[i];
    }
}

uint16_t& Date::operator[](const std::string& key) {
    if (key == "year") {
        return this->year();
    } else if (key == "month") {
        return this->month();
    } else if (key == "day") {
        return this->day();
    } else if (key == "hour") {
        return this->hour();
    } else if (key == "minute") {
        return this->minute();
    } else if (key == "second") {
        return this->second();
    }
    return (*this)[-1];
}
const uint16_t& Date::operator[](const std::string& key) const {
    if (key == "year") {
        return this->year();
    } else if (key == "month") {
        return this->month();
    } else if (key == "day") {
        return this->day();
    } else if (key == "hour") {
        return this->hour();
    } else if (key == "minute") {
        return this->minute();
    } else if (key == "second") {
        return this->second();
    }
    return (*this)[-1];
}

Date::operator time_t() const {
    std::tm tm;
    memset(&tm, 0, sizeof(tm));
    tm.tm_year = this->year() - 1900;
    tm.tm_mon  = this->month();
    tm.tm_mday = this->day() + 1;
    tm.tm_hour = this->hour();
    tm.tm_min  = this->minute();
    tm.tm_sec  = this->second();
    return mktime(&tm);
}
Date::operator std::tm*() const {
    time_t time = *this;
    return std::gmtime(&time);
}

std::string Date::to_string(const char* format/*=nullptr*/) const {
    if (format && strlen(format)) {
        std::tm* tm = *this;
        std::stringstream ss;
        ss << std::put_time(tm, format);
        return ss.str();
    }
    return std::to_string((time_t)*this);
}
std::tm* Date::to_gmtime() const {
    time_t time = *this;
    return std::gmtime(&time);
}
std::tm* Date::to_localtime() const {
    time_t time = *this;
    return std::localtime(&time);
}

//每年的第几周
uint16_t Date::getYearWeek() const {
    return getYearDay() / 7;
}
//每年的第几天
uint16_t Date::getYearDay() const {
    const std::tm* tm = *this;
    return tm->tm_yday;
}
//每周的第几天
uint16_t Date::getWeekDay() const {
    const std::tm* tm = *this;
    return tm->tm_wday;
}
//距离1970年1月1日第几天
uint16_t Date::getTimeDay() const {
    return *this / (24 * 3600);
}
void Date::setTimeDay(const uint16_t& day) {
    set((time_t)(day * 24 * 3600 + *this / (24 * 3600)));
}

bool Date::leap() const {
    return leap(year());
}
